/*******************************************************************************
 * FilePath    : /Src/BSP/SPI.c
 * Version     : 1.0
 * Brief       :
 * Author      : AndrewHu
 * Company     : Shanghai MacroGiga Electronics CO.,Ltd
 * Email       : Hubinbo@macrogiga.com
 * Date        : 2020-04-03 15:06:14
 * LastEditors : AndrewHu
 * LastEditTime: 2022-02-16 15:43:50
 * Description :
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <Includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function ----------------------------------------------------------*/
/* extern --------------------------------------------------------------------*/

/********************************************************************************************************
**函数信息 ：SPIM_TXEn(SPI_TypeDef* SPIx)
**功能描述 :关闭 SPI 在双向模式下的数据传输方向
**输入参数 ：SPI_TypeDef* SPIx,可选择SPI1,SPI2
**输出参数 ：无
********************************************************************************************************/
void SPIM_TXEn(SPI_TypeDef *SPIx)
{
	// Transmit Enable bit TXEN
	SPI_BiDirectionalLineConfig(SPIx, SPI_Direction_Tx);
}

/********************************************************************************************************
**函数信息 ：SPIM_TXDisable(SPI_TypeDef* SPIx)
**功能描述 :关闭 SPI 在双向模式下的数据传输方向
**输入参数 ：SPI_TypeDef* SPIx,可选择SPI1,SPI2
**输出参数 ：无
********************************************************************************************************/
void SPIM_TXDisable(SPI_TypeDef *SPIx)
{
	// disable TXEN
	SPI_BiDirectionalLineConfig(SPIx, SPI_Disable_Tx);
}

/********************************************************************************************************
**函数信息 ：SPIM_RXEn(SPI_TypeDef* SPIx)
**功能描述 :关闭 SPI 在双向模式下的数据传输方向
**输入参数 ：SPI_TypeDef* SPIx,可选择SPI1,SPI2
**输出参数 ：无
********************************************************************************************************/
void SPIM_RXEn(SPI_TypeDef *SPIx)
{
	// enable RXEN
	SPI_BiDirectionalLineConfig(SPIx, SPI_Direction_Rx);
}

/********************************************************************************************************
**函数信息 ：SPIM_RXDisable(SPI_TypeDef* SPIx)
**功能描述 :关闭 SPI 在双向模式下的数据传输方向
**输入参数 ：SPI_TypeDef* SPIx,可选择SPI1,SPI2
**输出参数 ：无
********************************************************************************************************/
void SPIM_RXDisable(SPI_TypeDef *SPIx)
{
	// disable RXEN
	SPI_BiDirectionalLineConfig(SPIx, SPI_Disable_Rx);
}
/*******************************************************************************
 * Function    : SPIM_Init
 * Brief       : SPI
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:50:40
 * Description :
 ******************************************************************************/
void SPIM_Init(SPI_TypeDef *SPIx, unsigned short spi_baud_div)
{
	SPI_InitTypeDef SPI_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;

	if (SPIx == SPI1)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); // SPI1 clk enable

		RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE);
		GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_0);
		GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_0);
		GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_0);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // spi1_cs  pb8
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_SetBits(GPIOB, GPIO_Pin_8); // csn=H

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // spi1_sck  pb3
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推免复用输出
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // spi1_mosi  pb5
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推免复用输出
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // spi1_miso  pb4
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //上拉输入
		GPIO_Init(GPIOB, &GPIO_InitStructure);
	}
	else if (SPIx == SPI2)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); // SPI2 clk enable
		// SPI_CSInternalSelected(SPI2, SPI_CS_BIT0, DISABLE);

		RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOD, ENABLE);
		GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_3);
		GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_4);
		GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_4);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; // spi2_cs  pb15
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_SetBits(GPIOB, GPIO_Pin_15); // csn=H

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; // spi2_sck  pb14
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推免复用输出
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; // spi2_mosi  pb13
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推免复用输出
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // spi2_miso  pb12
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //上拉输入
		GPIO_Init(GPIOB, &GPIO_InitStructure);
	}

	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_DataWidth = SPI_DataWidth_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;	 // mode0 SPI_CPOL_Low, SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // mode3 SPI_CPOL_High,SPI_CPHA_2Edge
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = spi_baud_div;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_Init(SPIx, &SPI_InitStructure);

	SPI_Cmd(SPIx, ENABLE); // Enables the specified SPI peripheral SPI使能、主机模式 8位数据模式 SPI 的波特率

	SPIM_TXEn(SPIx);
	SPIM_RXEn(SPIx);

	// IRQ - pa12(MS1793)  PD2(MS1791)
	GPIO_InitStructure.GPIO_Pin = IRQ_BLE_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
	GPIO_Init(IRQ_BLE_PORT, &GPIO_InitStructure);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

	SYSCFG_EXTILineConfig(IRQ_EXTIPORT, IRQ_EXTISOURCE);
	EXTI_InitStructure.EXTI_Line = IRQ_EXTI;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel = IRQ_EXTNUMBER;
	NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_SetPriority(IRQ_EXTNUMBER, (1 << __NVIC_PRIO_BITS) - 1);
}
/*******************************************************************************
 * Function    : SPI_WriteRead
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:52:13
 * Description :
 ******************************************************************************/
unsigned char SPI_WriteRead(unsigned char SendData, unsigned char WriteFlag) // porting api
{
	SPI_BLE->TXREG = SendData;
	while (!(SPI_BLE->CSTAT & SPI_FLAG_TXEPT))
		;
	while (!(SPI_BLE->CSTAT & SPI_FLAG_RXAVL))
		;
	return SPI_BLE->RXREG;
}
/*******************************************************************************
 * Function    : SPI_CS_Enable_
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:50:24
 * Description :
 ******************************************************************************/
void SPI_CS_Enable_(void) // porting api
{
	GPIO_ResetBits(CSN_BLE_PORT, CSN_BLE_PIN);
}
/*******************************************************************************
 * Function    : SPI_CS_Disable_
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:50:31
 * Description :
 ******************************************************************************/
void SPI_CS_Disable_(void) // porting api
{
	GPIO_SetBits(CSN_BLE_PORT, CSN_BLE_PIN);
}
/*******************************************************************************
 * Function    : IsIrqEnabled
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:52:37
 * Description :
 ******************************************************************************/
char IsIrqEnabled(void) // porting api
{
	return (!(GPIO_ReadInputData(IRQ_BLE_PORT) & IRQ_BLE_PIN));
}
/*******************************************************************************
 * Function    : SPI_WriteBuf
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:52:22
 * Description :
 ******************************************************************************/
unsigned char SPI_WriteBuf(unsigned char reg, unsigned char const *pBuf, unsigned char len)
{
	unsigned char result = 0;
	unsigned char i;

	SPI_CS_Enable_();

	SPI_WriteRead(reg, 1);

	for (i = 0; i < len; i++)
	{
		SPI_WriteRead(*pBuf++, 1);
	}

	SPI_CS_Disable_();

	return result;
}
/*******************************************************************************
 * Function    : SPI_ReadBuf
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:52:33
 * Description :
 ******************************************************************************/
unsigned char SPI_ReadBuf(unsigned char reg, unsigned char *pBuf, unsigned char len)
{
	unsigned char result = 0;
	unsigned char i;

	SPI_CS_Enable_();

	result = SPI_WriteRead(reg, 1);

	for (i = 0; i < len; i++)
	{
		*(pBuf + i) = SPI_WriteRead(0xff, 0);
	}

	SPI_CS_Disable_();

	return result;
}
